package com.vogue.supplymall.account.shiro.filter;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.vogue.supplymall.account.shiro.bean.TokenBean;
import com.vogue.supplymall.account.shiro.token.MallUsernamePasswordToken;
import com.vogue.supplymall.common.domain.tool.CodeProcessUtils;

/**
 * 登录功能过滤器<br>
 * 
 * @author 崔岳
 *
 */
public class LoginAuthenticationFilter extends AuthenticatingFilter {

	public static final String DEFAULT_ERROR_KEY_ATTRIBUTE_NAME = "shiroLoginFailure";

	public static final String DEFAULT_USERNAME_PARAM = "username";
	public static final String DEFAULT_PASSWORD_PARAM = "password";
	public static final String DEFAULT_REMEMBER_ME_PARAM = "rememberMe";

	public static final Logger LOGGER_LOGINAUTHENTICATIONFILTER = LoggerFactory.getLogger(LoginAuthenticationFilter.class);
	private String usernameParam = DEFAULT_USERNAME_PARAM;
	private String passwordParam = DEFAULT_PASSWORD_PARAM;
	private String rememberMeParam = DEFAULT_REMEMBER_ME_PARAM;
	private String failureKeyAttribute = DEFAULT_ERROR_KEY_ATTRIBUTE_NAME;
	
	protected boolean isRememberMe(ServletRequest request) {
		return DEFAULT_REMEMBER_ME_PARAM.equals(rememberMeParam);
	}

	@Override
	protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
			ServletResponse response) {
		request.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, e.getClass().getName());
		return false;
	}
	
	@Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
            ServletRequest request, ServletResponse response) throws Exception {
		return true;
	}
	
	@Override
	protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
		Map<String, String> info = getLogininfo(request, response);
		if (info != null) {
			request.setAttribute("username", info.get("username"));
			request.setAttribute("password", info.get("password"));
			return new MallUsernamePasswordToken(info.get("username"), info.get("password"), isRememberMe(request));
		} else {
			return new MallUsernamePasswordToken("", "", isRememberMe(request));
		}
	}

	public Map<String, String> getLogininfo(ServletRequest request, ServletResponse respons) throws Exception{
		String username = request.getParameter(getUsernameParam());
		String password = request.getParameter(getPasswordParam());
		if (username == null) {
			BufferedReader br = new BufferedReader(
					new InputStreamReader((ServletInputStream) request.getInputStream(), "utf-8"));
			StringBuffer sb = new StringBuffer("");
			String temp;
			try {
				while ((temp = br.readLine()) != null) {
					sb.append(temp);
				}
			}finally {
				if(br != null) {
//					br.close();
//					request.setAttribute(ConstantBean.REQUEST_STREAM_CLOSE_FLAG, true);
				}				
			}			
			String params = sb.toString();
			Gson json = new Gson();
			TokenBean bean = json.fromJson(params, TokenBean.class);
			if (bean != null) {
				// logininfo有内容用此处的值进行转化登录，如果为空直接用username和password去验证
				if (StringUtils.isNotEmpty(bean.getLogininfo())) {
					String loginInfo = new String(CodeProcessUtils.decode(bean.getLogininfo()));
					TokenBean loginBean = json.fromJson(loginInfo, TokenBean.class);
					username = loginBean.getUsername();
					password = loginBean.getPassword();	
				} else {
					username = bean.getUsername();
					password = bean.getPassword();
				}
			}
		}
		String loginInfo = CodeProcessUtils
				.encode(("{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}").getBytes());
		request.setAttribute(com.vogue.supplymall.account.domain.bean.ConstantBean.REQ_LOGIN_INFO_KEY, loginInfo);
		LOGGER_LOGINAUTHENTICATIONFILTER.debug(loginInfo);
		Map<String, String> info = null;
		if (username != null && password != null) {
			info = new HashMap<String, String>();
			info.put("username", username);
			info.put("password", password);
		} 
		return info;
	}
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		HttpServletRequest httpRequest = WebUtils.toHttp(request);
		//OPTIONS 实际是不做业务处理的一次试探访问，因此不对此请求进行业务限制
//		if("OPTIONS".equals(httpRequest.getMethod())) {
//			return true;
//		}
		
		//如果已经登录了直接过 begin
		Subject subject = SecurityUtils.getSubject();
		if(subject != null && subject.getPrincipal() != null) {
			return true;
		}
		//如果已经登录了直接过 end
		
		boolean flag = true;
//		int errcode = -1;
//		String className = null;
		if (request.getAttribute(getFailureKeyAttribute()) != null) {
			flag = false;
//			className = (String)request.getAttribute(getFailureKeyAttribute());
		} else {
			if (isLoginRequest(request, response)) {
				flag = true;
				getLogininfo(request, response);
			} else {
				if (executeLogin(request, response)) {
					flag = true;
				} else {
//					request.setAttribute(ConstantBean.REQUEST_EXCEPTION_KEY, new IncorrectCredentialsException());
					flag = false;
//					className = (String)request.getAttribute(getFailureKeyAttribute());
				}
			}
		}
		
		flag=true;
		/*if(!flag) {
			if(className != null) {
				if(className.equals(org.apache.shiro.authc.UnknownAccountException.class.getName())) {
					errcode = ErrorCode.IncorrectCredentials.getCode();
				}else if(className.equals(org.apache.shiro.authc.IncorrectCredentialsException.class.getName())) {
					errcode = ErrorCode.IncorrectCredentials.getCode();
				}else if(className.equals(org.apache.shiro.authc.ExcessiveAttemptsException.class.getName())) {
					errcode = ErrorCode.ExcessiveAttempts.getCode();
				}else if(className.equals(org.apache.shiro.authc.LockedAccountException.class.getName())) {
					errcode = ErrorCode.LockedAccount.getCode();
				}
			}
			String msg = null;
			Locale locale = LocaleContextHolder.getLocale();
			if(messageSource == null) {
				errcode = -1;
				msg = messageSource.getMessage(""+errcode, new Object[] {"messageSource is null"}, locale);
			}else {
				msg = messageSource.getMessage(""+errcode, null, locale);
			}
			HttpServletResponse httpResponse;
			HttpServletRequest httpRequest;
			Map<String, Object> map = new HashMap<String, Object>();
			httpResponse = WebUtils.toHttp(response);
			httpRequest = WebUtils.toHttp(request);
			WebUtils.saveRequest(request);
			if (httpRequest.getRequestURI() == null) {
				map.put("requestUri", "");
			} else {
				map.put("requestUri", httpRequest.getRequestURI());
			}
			if (httpRequest.getRequestURL() == null) {
				map.put("requestUrl", "");
			} else {
				map.put("requestUrl", httpRequest.getRequestURL());
//				System.out.println(httpRequest.getRequestURL());
			}
			
			PrintWriter out = null;
			
			System.out.println(httpRequest.getMethod());
			if("OPTIONS".equals(httpRequest.getMethod())) {
				return true;
			}
			httpResponse.setHeader("Access-Control-Allow-Origin", "*");
			httpResponse.setHeader("Access-Control-Allow-Methods", "GET,HEAD,POST,PUT,DELETE,OPTIONS");
			httpResponse.setHeader("Access-Control-Allow-Headers","Content-Type");
			httpResponse.setHeader("Access-Control-Allow-Origin", "*");    
			httpResponse.setHeader("Access-Control-Max-Age", "3600");  
			httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with"); 
			
			httpResponse.setStatus(200, "redirect");
			httpResponse.setCharacterEncoding("UTF-8");
//			httpResponse.setContentType("text/plain; charset=utf-8");
			httpResponse.setContentType("application/json");

			try {
				out = httpResponse.getWriter();
//				ErrorMsg ret = new ErrorMsg(errcode, msg);
//				JSONObject responseJSONObject = new JSONObject(ret);
				out.append("{\"msg\":\""+msg+"\",\"code\":\""+errcode+"\"}");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (out != null) {
					out.close();
				}
			}
		}*/
		return flag;		
	}

	public String getFailureKeyAttribute() {
		return failureKeyAttribute;
	}

	public void setFailureKeyAttribute(String failureKeyAttribute) {
		this.failureKeyAttribute = failureKeyAttribute;
	}

	public String getUsernameParam() {
		return usernameParam;
	}

	public void setUsernameParam(String usernameParam) {
		this.usernameParam = usernameParam;
	}

	public String getPasswordParam() {
		return passwordParam;
	}

	public void setPasswordParam(String passwordParam) {
		this.passwordParam = passwordParam;
	}

	public String getRememberMeParam() {
		return rememberMeParam;
	}

	public void setRememberMeParam(String rememberMeParam) {
		this.rememberMeParam = rememberMeParam;
	}

}
